#ifndef ASYNCFILEBUFFER_H
#define ASYNCFILEBUFFER_H

#include "filebufferwithsignals.h"
#include <QRunnable>
#include <QThreadPool>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>

/*!
 * \brief The FbCommand class
 * Служебный класс, используемый для передачи назначенной команды для выполнения рабочим потоком
 * буфера файлов
 */
class FbCommand
{
public:
    //! Тип команды
    enum Type {
        //! Команда не назначена
        NOP,
        //! Назначена команда на загрузку файла
        LOAD,
        //! Назначена команда на запись файла
        SAVE,
        //! Назначена команда очистки памяти
        CLEAR
    };
    FbCommand();
    //! Получает тип назначенной команды
    Type getType();
    //! Получает имя файла, над которым требуется выполнить определенную операцию
    QString getFileName();
    //! Сброс команды (команда не назначена)
    void reset();
    //! Установка команды
    /*!
     * \brief set
     * \param type тип команды, которую требуется назначить
     * \param fileName имя файла, над которым требуется выполнить операцию
     */
    void set(Type type, QString fileName);

protected:

    Type type;
    QString fileName;
};

/*!
 * \brief The AsyncFileBuffer class
 * Асинхронная потокобезопасная реализация буфера файлов. Использует для оповещения о результатах операций
 * с файлами механизм сигналов.
 */
class AsyncFileBuffer : public FileBufferWithSignals, public QRunnable
{

public:
    AsyncFileBuffer();

    ~AsyncFileBuffer();

    QString holdLoad();

    void loadFile(QString fName);

    QString holdSave();

    void saveFile(QString fName);

    void release();

    QString holdClear();

    void clearData();

    //! Возвращает описание ошибки последней операции, если она была
    /*!
     * \brief getLastError
     * \return описание ошибки последней операции. Если ошибки не было, то QString()
     * Если в данный момент операция уже идет, то дожидается окончания её выполнения
     */
    QString getLastError();

    IFileBuffer::State getState();

    QString getFileName();

    qint64  getFileSize();

    qint64 getBytesProcessed();

public slots:

    void trigger();

    void stop();

protected:

    bool canWork();

    void enableWork();

    enum WorkStatus {
        OK, PAUSED, CANCELLED
    };
    WorkStatus workStatus;
    QMutex workStatusGuard;
    QWaitCondition workStatusDefined;

    QMutex stateGuard;
    void setState(State newState);

    QMutex bytesProcessedGuard;
    void setBytesProcessed(qint64 newSize);
    void incBytesProcessed(qint64 incSize);

    QMutex fileSizeGuard;
    void setFileSize(qint64 newSize);

    QMutex fileNameGuard;
    void setFileName(QString newFileName);

    QThreadPool *worker;

    FbCommand cmd;
    QMutex cmdGuard;
    bool hold();

    QMutex runGuard;
    void run();
    bool isRunning;
};

#endif // ASYNCFILEBUFFER_H
